home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / net / parnet-3.2 / extras / parpc / amigafiles / sources / par.asm < prev    next >
Assembly Source File  |  1995-03-09  |  20KB  |  705 lines

  1.  
  2.         ;   PARALLEL PORT NETWORK LOW LEVEL ROUTINES
  3.         ;
  4.         ;   CABLE:  Connect D7-D0,SEL,POUT, and BUSY across,
  5.         ;        Connect ACK to SEL locally:
  6.         ;        Connect GND lines indicated
  7.         ;
  8.         ;   (2-9)   D7-D0   ------------    D7-D0
  9.         ;   (12)    POUT    ------------    POUT
  10.         ;   (11)    BUSY    ------------    BUSY       PARALLEL PORT
  11.         ;   (13)    SEL     --+------+--    SEL
  12.         ;   (10)    ACK     -/        \-    ACK
  13.         ;   (18-22) GND     ------------    GND
  14.         ;
  15.         ;   WARNING: you cannot connect RI on the serial port to your
  16.         ;         modem because it interferes with the parallel
  17.         ;         port's SEL line in this configuration.
  18.         ;
  19.         ;   *    28K/sec bandwidth
  20.         ;   *    # machines depends on extra hardware for buffering,
  21.         ;    but 3 ought to work fine without any extra hardware.
  22.         ;
  23.         ;    (network protocol can now handle 254)
  24.         ;
  25.         ;   Data Line Definitions:
  26.         ;    CIAA PORTB :    D7-D0    used for byte data transfer
  27.         ;    CIAB PORTA :    D2-D0    used for line aquisition and
  28.         ;                handshaking (SEL,POUT,BUSY)
  29.         ;
  30.         ;   All lines pulled up.  Thus, asserted state is a 0.    Idle
  31.         ;   state is an undriven (1).  Protocol transfers a byte at
  32.         ;   a time.  Protocol is ethernet style with a small window
  33.         ;   of error in the line aquisition routine.
  34.         ;
  35.         ;   Note:   Timeouts should be set around a second.  Ideally
  36.         ;        defaults should be fixed on faster machines.
  37.         ;
  38.         ;   CIAB PORTA    D0  ~ACK    hand shake
  39.         ;        D1  ~REQ    hand shake
  40.         ;        D2   CTL    1 = special byte, 0 = data byte.
  41.         ;                (for address mark, valid when ~REQ
  42.         ;                 goes low.    For EOP mark, sample
  43.         ;                 when ~REQ goes high)
  44.         ;
  45.         ;                PROTOCOL
  46.         ;
  47.         ;   HandShake    (Reader <- Writer transfer).  A Handshake
  48.         ;        sequence transfers TWO bytes of information.
  49.         ;
  50.         ;        WRITER                READER
  51.         ;    |-> place data, ~REQ->0
  52.         ;    |                 wait for ~REQ->0
  53.         ;    |                 read data & store
  54.         ;    |                 set ~ACK->0
  55.         ;    |   wait ~ACK->0
  56.         ;    |   place data, ~REQ->1
  57.         ;    |                 wait for ~REQ->1
  58.         ;    |                 read data & store
  59.         ;    |                 set ~ACK->1
  60.         ;    |   wait ~ACK->1
  61.         ;    |<- LOOP  (2 bytes written)      LOOP  (2 bytes read)
  62.         ;
  63.         ;
  64.         ;   Read:   (1) Determine if your machine is being addressed
  65.         ;        (~REQ=0, data=myaddress, CTL=1)
  66.         ;        (1) set DDR for ~ACK to output and
  67.         ;        (2) Handshake sequence for the address mark, only
  68.         ;        first byte valid.
  69.         ;        (3) Handshake sequence for data util rcv byte
  70.         ;        with CTL = 1 (EOP), byte must == 0.
  71.         ;        (4) Set ~ACK (bit 0) to input
  72.         ;
  73.         ;   Write:  (1) AQUIRE THE NETWORK (see below)
  74.         ;        involves gaining control and then setting the
  75.         ;        DDR for CTL and ~REQ to outputs.
  76.         ;
  77.         ;        Also checks if somebody is writing to us,
  78.         ;        in which case -2 is returned instantaniously
  79.         ;        indicating we should do a ParRead().
  80.         ;
  81.         ;        (2) Handshake sequence for address mark, send dest
  82.         ;        address (second byte garbage).  Note that CTL->1
  83.         ;        *BEFORE* we set ~REQ->0
  84.         ;        (3) Handshake sequence for data bytes
  85.         ;        (4) Handshake sequence for EOP mark (Note that CTL->1
  86.         ;        *AFTER* we get the ~ACK->1 and before release
  87.         ;        ~REQ (->1).  Only firstbyte valid and set to 0.
  88.         ;
  89.         ;        (5) Set ~ACK and ~CTL to inputs
  90.         ;
  91.         ;   AQUIRE: Line aquisition prevents two people from writing to
  92.         ;        the net at the same time.
  93.         ;
  94.         ;        * A line is considered aquired if ANY of the 3
  95.         ;          control lines is 0.
  96.         ;        * If network is not aquired:
  97.         ;        - set ~ACK to output and 1
  98.         ;        - bclr ~ACK to 0 and bne success
  99.         ;          (else set ~ACK to input and try again)
  100.         ;        - set data lines to output and place my address
  101.         ;          (Must ]be done before CTL is glitched)
  102.         ;        - set ~CTL to output and 1
  103.         ;        - set CTL to 0 and then 1 (glitch it) to cause
  104.         ;          FLAG interrupt on all other machines
  105.         ;        - set ~REQ to output and 0 (beginning of handshake
  106.         ;          sequence)
  107.         ;        - lastly, release ~ACK by setting it to an input
  108.         ;
  109.         ;          Note that at all times at least one line is a 0
  110.         ;          so no other machine will attempt to aquire the net.
  111.         ;
  112.         ;   Note that the destination address is placed on the data
  113.         ;   lines after we have aquired the line but before we glitch
  114.         ;   the CTL line to cause an interrupt.  This allows the
  115.         ;   other machines to instantaniously determine who is being
  116.         ;   addressed.
  117.         ;
  118.         ;   Note that the CTL line gets glitched at the end of a packet
  119.         ;   too for the EOP mark.  In this case there is a 0 on the
  120.         ;   data lines so while an interrupt is generated, nobody
  121.         ;   thinks they are being addressed.
  122.  
  123.         INCLUDE "exec/types.i"
  124.         INCLUDE "exec/execbase.i"
  125.  
  126.         XREF    _intena
  127.  
  128. DISABLE     MACRO
  129.         MOVE.W    #$04000,_intena     *(NOT IF_SETCLR)+IF_INTEN
  130.         ADDQ.B    #1,IDNestCnt(A6)
  131.         ENDM
  132.  
  133. ENABLE        MACRO
  134.         SUBQ.B    #1,IDNestCnt(A6)
  135.         BGE.S    ENABLE\@
  136.         MOVE.W    #$0C000,_intena     *IF_SETCLR+IF_INTEN
  137. ENABLE\@
  138.         ENDM
  139.  
  140.  
  141.         section __MERGED,DATA
  142.  
  143.         xdef    _ParLLTimeout
  144.         xdef    _ParDAT
  145.         xdef    _ParDDR
  146.         xdef    _ParCollision1
  147.         xdef    _ParCollision2
  148.         xdef    _ParDebug
  149.  
  150.         ;   Note, the timeout is set manually on init by using the
  151.         ;   timer.device to time one second.
  152.  
  153. _ParLLTimeout    dc.l    1000000     ; default timeout value (count). 1 second
  154. _ParDAT     dc.l    $BFE101     ; data port
  155. _ParDDR     dc.l    $BFE301     ; data ddr
  156. _ParCAT     dc.l    $BFD000     ; ctl  port (D0-D2)
  157. _ParCDR     dc.l    $BFD200     ; ctl  ddr  (D0-D2)
  158. _ParNetAddr    dc.b    0        ; default network address (msb 4 bits)
  159. _DummyBuf    dc.b    0        ; dummy buffer
  160.         dc.b    0        ; dummy buffer
  161.         dc.b    0        ; pad
  162. _ParCollision1    dc.l    0        ; statistics
  163. _ParCollision2    dc.l    0        ;
  164. Null        dc.l    0        ; always 0
  165.         dc.l    0        ; always 0
  166.  
  167. _ParDebug    ds.l    16        ; 16 longword debug entries
  168.  
  169.         section text,code
  170.  
  171.         ;   (void) ParAddress(myaddr)
  172.         ;    Set my address to (1-254)
  173.         ;
  174.         ;    0 and 255 are reserved!
  175.         ;
  176.         ;   int  = ParDataReady()
  177.         ;    returns 1  if packet pending
  178.         ;    returns 0  if line is currently idle
  179.         ;    returns -1 if packet isn't for you
  180.         ;
  181.         ;    if line has been aquired but no control address has been
  182.         ;    put on it yet, ParDataReady() will wait for a control
  183.         ;    address.  Thus, after a signal, a single call to
  184.         ;    ParDataReady() should suffice.
  185.         ;
  186.         ;   n = ParReadV (buf1, bytes1, buf2, bytes2, ..., NULL, NULL);
  187.         ;    (buffer sizes must be even)
  188.         ;   n = ParRead (buf, bytes)
  189.         ;    read a pending packet.    Returns n = -1 (1 second timeout
  190.         ;    no packet pending), n = 0 to bytes -1 (1 second timeout
  191.         ;    after transmission interrupted), n = bytes (success),
  192.         ;    or n > bytes (transmitting machine's packet was larger
  193.         ;    than we can handle, extra bytes thrown out)
  194.         ;
  195.         ;    NOTE: requesting an odd number of bytes is O.K. but
  196.         ;          if you request N where N is odd and the writer
  197.         ;          sends N + 1 you will never know (N will be
  198.         ;          returned).  See ParWrite() below
  199.         ;
  200.         ;   n = ParWriteV (destadr, buf1, bytes1, buf2, bytes2, ..., NULL, NULL);
  201.         ;    (buffer sizes must be even)
  202.         ;   n = ParWrite(destadr, buf, bytes)
  203.         ;    write a packet.  Returns:
  204.         ;    n = -2    Cannot write anything, a packet is pending
  205.         ;        (instantanious)
  206.         ;    n = -1    Destination machine does not respond (1 sec to)
  207.         ;    n = N    N bytes written ok (success if n == bytes)
  208.         ;
  209.         ;    NOTE: sending an odd number of bytes is O.K. but if
  210.         ;    you write N where N is odd and the reader requests
  211.         ;    N + 1 he will get N + 1 the last byte being garbage.
  212.         ;
  213.         ;
  214.         ;   CIAA PORTB    :  DATA ONLY
  215.         ;   CIAB PORTA    :  D0    ~DAck
  216.         ;           D1    ~DRdy
  217.         ;           D2    Ctl
  218.  
  219.         xdef    _ParRead
  220.         xdef    _ParReadV
  221.         xdef    _ParWrite
  222.         xdef    _ParWriteV
  223.         xdef    _ParAddress
  224.         xdef    _ParDataReady
  225.         xdef    _LongCheckSum
  226.         xdef    _Time10000
  227.  
  228. _ParAddress:    move.l    4(sp),D0                ;   address 1-254
  229.         move.b    D0,_ParNetAddr        ;   store
  230.         rts
  231.  
  232.         ;   ParDataReady()
  233.         ;
  234.         ;   -1    packet isn't for you
  235.         ;   0    line is idle
  236.         ;   1    packet probably pending for you
  237.  
  238. _ParDataReady:    move.l    _ParDAT,A0        ;   data register
  239.         move.l    _ParCAT,A1        ;   data control register
  240.  
  241. .pdstable    move.b    (A1),D0
  242.         move.b    (A0),D1
  243.         cmp.b    (A1),D0                 ;   control lines stable?
  244.         bne    .pdstable
  245.  
  246.         ;   Now, ParDataReady might be called after the sending machine
  247.         ;   has aquired but before it can assert REQ.  However, the
  248.         ;   sending machine has already (guarenteed) placed its address
  249.         ;   on the data port.  So while the address matches, loop while
  250.         ;   REQ not asserted.
  251.  
  252.         btst.l    #1,D0            ;   ~Req asserted?
  253.         beq    .pd10            ;   beq yes
  254.         cmp.b    _ParNetAddr,D1        ;   no, does data match anyway?
  255.         beq    .pdstable        ;   YES, loop until get ~REQ or
  256.         bra    .pdfail         ;   data bad.
  257.  
  258. .pd10        btst.l    #2,D0            ;   yes, Ctl ?
  259.         beq    .pdrn            ;   no, middle of some packet
  260.         cmp.b    _ParNetAddr,D1        ;   yes, my address?
  261.         bne    .pdrn
  262.         moveq.l #1,D0            ;   yes, packet (probably) for us
  263.         rts
  264.  
  265. .pdfail     btst.l    #2,D0            ;   fail due to ~Req not asserted
  266.         beq    .pdrn            ;   Ctl = 0, line busy
  267. .pdr0        moveq.l #0,D0            ;   line idle
  268.         rts
  269. .pdrn        moveq.l #-1,D0            ;   line busy, packet not for me
  270.         rts
  271.  
  272. _ParReadV:                    ;   Read Into Vector
  273.         movem.l D2-D7/A2-A5,-(sp)
  274.         lea    12+40(sp),A3
  275.         bra    .rm000
  276.  
  277. _ParRead:
  278.         movem.l D2-D7/A2-A5,-(sp)
  279.         lea    Null,A3         ;   Pointer to next vector
  280. .rm000        move.l    4+40(sp),A0             ;   A0 = buffer to read into
  281.         move.l    8+40(sp),D7             ;   D7 = # bytes to read (maximum)
  282.         move.l    _ParDAT,A1        ;   A1 = data reg
  283.         move.l    _ParDDR,A2        ;   A2 = ddr
  284.         move.l    _ParCAT,A4        ;   A4 = data reg
  285.         move.l    _ParCDR,A5        ;   A5 = ddr
  286.  
  287.         move.b    #0,(A2)                 ;   ensure all are inputs
  288.         bclr.b    #0,(A5)
  289.         bclr.b    #1,(A5)
  290.         bclr.b    #2,(A5)
  291.  
  292.         move.l    _ParLLTimeout,D5    ;   D5 = timeout load
  293.         moveq.l #-1,D6            ;   D6 = # bytes read so far
  294.  
  295.         ;   WAIT LOOK FOR ADDRESS MARK
  296.         ;
  297.         ;   Ctl = 1, ~DReq = 0
  298.  
  299.         move.l    D5,D4            ;   D4 = timeout countdown
  300. .rmstab     move.b    (A4),D0                 ;   control data
  301.         move.b    (A1),D1                 ;   data data (network addr)
  302.         cmp.b    (A4),D0
  303.         bne    .rmstab
  304.         btst.l    #2,D0            ;   expect CTL = 1
  305.         beq    .rms1            ;   nope
  306.         btst.l    #1,D0            ;   expect ~REQ = 0
  307.         beq    .rms2            ;   yes
  308. .rms1
  309.         add.l    #1,_ParDebug+0
  310.         subq.l    #1,D4            ;   timeout
  311.         bne    .rmstab
  312.         bra    .rmend            ;   no address mark!
  313.  
  314. .rms2        cmp.b    _ParNetAddr,D1        ;   my address?
  315.         bne    .rms1            ;   no, timeout loop
  316.  
  317.         ;   My address, ~Ack byte.
  318.  
  319.         bclr.b    #0,(A4)                 ;   set ~ACK to 0
  320.         bset.b    #0,(A5)                 ;   set to output
  321.  
  322.         move.l    D5,D4            ;   reset timeout
  323. .rms4        btst.b    #1,(A4)                 ;   wait for ~REQ to go away
  324.         bne    .rms5
  325.         add.l    #1,_ParDebug+4
  326.         subq.l    #1,D4
  327.         bne    .rms4
  328.         moveq.l #-2,D6            ;   ~REQ not released ?????
  329.         bra    .rmend
  330.  
  331. .rms5        bset.b    #0,(A4)                 ;   release ~ACK
  332.         moveq.l #0,D6            ;   set # bytes read to 0
  333.         bra    .rms10            ;   skip past move
  334.  
  335.         ;   MAIN READ LOOP
  336.         ;
  337.         ;   D6 holds cnt, A0 buffer ptr, D0-D4 free to allocate
  338.  
  339. .rms10loop
  340.         move.b    D0,(A0)                 ;   store data
  341.         addq.l    #1,A0            ;   next addr.
  342.  
  343. .rms10        btst.b    #1,(A4)                 ;   wait for ~REQ asserted
  344.         beq    .rms20
  345.         btst.b    #1,(A4)
  346.         beq    .rms20
  347.         move.l    D5,D4            ;   load timeout
  348. .rms11        btst.b    #1,(A4)                 ;   wait for ~REQ asserted w/to
  349.         beq    .rms20
  350.         add.l    #1,_ParDebug+8
  351.         subq.l    #1,D4
  352.         bne    .rms11
  353.         bra    .rmend
  354.  
  355. .rms20        move.b    (A1),D0                 ;   get data and
  356.         bclr.b    #0,(A4)                 ;   assert ~ACK
  357.  
  358.         ;   note, on CTL = 1 end sequence this data item is a dummy
  359.  
  360.         move.b    D0,(A0)                 ;   store data
  361.         addq.l    #1,A0            ;   next addr.
  362.         addq.l    #2,D6            ;   optimized but not quite
  363.                         ;   true, we've only written 1 sf.
  364.         btst.b    #1,(A4)                 ;   wait for ~REQ released
  365.         bne    .rms30
  366.         btst.b    #1,(A4)
  367.         bne    .rms30
  368.         move.l    D5,D4
  369. .rms21        btst.b    #1,(A4)                 ;   wait for ~REQ rel w/ to
  370.         bne    .rms30
  371.         add.l    #1,_ParDebug+12
  372.         subq.l    #1,D4
  373.         bne    .rms21
  374.         bra    .rmendsub        ;   sub because D6 is 2 ahead
  375.  
  376. .rms30        move.b    (A1),D0                 ;   get data
  377.         move.b    (A4),D1                 ;   get CTL status
  378.         bset.b    #0,(A4)                 ;   release ~ACK
  379.         btst.l    #2,D1            ;   EOP if CTL = 1
  380.         bne    .rmeop
  381.  
  382.         ;   CANNOT STORE DATA HERE!  In case odd # bytes requested,
  383.         ;   second byte would overflow buffer
  384.  
  385.         subq.l    #2,D7            ;   # bytes remaining
  386.         bgt    .rms10loop
  387.         bne    .rmnlb
  388.         move.b    D0,(A0)                 ;   if D7 = 0 its even and we
  389.                         ;   should store the last byte
  390. .rmnlb        cmp.l    #-1,D7            ;   -1 = was odd #
  391.         bne    .rmeven         ;   fixup count
  392.         subq.l    #1,D6
  393.  
  394. .rmeven
  395. .rmsev0     tst.l    (A3)                    ;   if next buffer NULL
  396.         beq    .rmovflow
  397.         move.l    (A3)+,A0                ;   next buffer
  398.         move.l    (A3)+,D7
  399.         beq    .rmsev0         ;   0 bytes, goto next buffer
  400.         bra    .rms10            ;   loop, continue reading
  401.  
  402. .rmovflow
  403.         lea    _DummyBuf,A0        ;   overflow, dummy buffer
  404.         bra    .rms10
  405.  
  406. .rmeop        tst.b    D0            ;   EOP data better be 0!
  407.         beq    .rmendsub
  408.         moveq.l #-3,D6
  409.         bra    .rmend
  410.  
  411. .rmendsub    subq.l    #2,D6            ;   because we were two ahead
  412.  
  413. .rmend        bset.b    #0,(A4)                 ;   active pull up before (?)
  414.         bclr.b    #0,(A5)                 ;   setting ~ACK to input
  415.         move.l    D6,D0            ;   return value
  416.         movem.l (sp)+,D2-D7/A2-A5       ;   restore registers
  417.         rts
  418.  
  419. _ParWriteV:    movem.l D2-D7/A2-A6,-(sp)       ;   write vector
  420.         lea    16+44(sp),A3
  421.         bra    .wm000
  422.  
  423. _ParWrite:
  424.         movem.l D2-D7/A2-A6,-(sp)
  425.         lea    Null,A3
  426. .wm000        move.l    4+44(sp),D3             ;   D3 = destination address
  427.         move.l    8+44(sp),A0             ;   A0 = buffer to write
  428.         move.l    12+44(sp),D7            ;   D7 = # bytes to write
  429.         move.l    _ParDAT,A1        ;   A1 = data reg
  430.         move.l    _ParDDR,A2        ;   A2 = ddr
  431.         move.l    _ParCAT,A4        ;   A4 = data reg
  432.         move.l    _ParCDR,A5        ;   A5 = ddr
  433.         move.l    4,A6            ;   SYSBase
  434.  
  435.         move.b    #0,(A2)
  436.         and.b    #%11111000,(A5)
  437.         move.l    _ParLLTimeout,D5    ;   D5 = timeout load
  438.  
  439.         move.l    D5,D4            ;   D4 = timeout countdown
  440.         moveq.l #-2,D6            ;   D6 = # bytes written
  441.  
  442.         ;   AQUIRE THE LINE USING ~ACK
  443.  
  444. .wmstab
  445.         bset.b    #0,(A4)                 ;   so is a 1 when we set it to w
  446.  
  447.         DISABLE
  448.  
  449.         move.b    (A4),D0                 ;   get stable data
  450.         move.b    (A1),D1
  451.         cmp.b    (A4),D0
  452.         beq    .wmstab1
  453.  
  454.         ENABLE
  455.  
  456.         bra    .wmstab
  457.  
  458.         ;   Ints still disabled
  459.         ;   D0 holds ~ACK ~REQ CTL status
  460.  
  461. .wmstab1    and.b    #%111,D0        ;   ~ACK=1, ~REQ=1, CTL=1
  462.         cmp.b    #%111,D0
  463.         beq    .wm02
  464.  
  465.         ;   no, if CTL = 1, ~REQ = 0, and D1 = my address then
  466.         ;   return w/ -2
  467.  
  468.         btst.l    #1,D0
  469.         bne    .wm01
  470.         btst.l    #2,D0
  471.         beq    .wm01
  472.         cmp.b    _ParNetAddr,D1        ;   somebody calling me?
  473.         bne    .wm01
  474.  
  475.         ENABLE
  476.         bra    .wmend
  477.  
  478. .wm01
  479.         ENABLE
  480.  
  481.         add.l    #1,_ParDebug+16
  482.         subq.l    #1,D4
  483.         bne    .wmstab
  484.         bra    .wmend
  485.  
  486.         ;   interrupts still disabled
  487.         ;   we almost own the line
  488.  
  489. .wm02        bset.b    #0,(A5)                 ;   set ~ACK to an output
  490.         nop
  491.         bclr.b    #0,(A4)                 ;   assert ~ACK
  492.         bne    .wm05            ;   was released before, have line!
  493.  
  494.                         ;   don't have line,
  495.         bclr.b    #0,(A5)                 ;   set back to input
  496.         bra    .wm01
  497.  
  498.         ;   Line now aquired.
  499.  
  500. .wm05
  501.         ENABLE
  502.  
  503.         move.b    #$FF,(A2)               ;   set data ddr to outputs
  504.         move.b    D3,(A1)                 ;   set data lines to our addr
  505.  
  506.         ;   Before asserting ~REQ pulse CTL to cause interrupt on remote
  507.         ;   machines.  Note that our address is already on the data
  508.         ;   lines.
  509.  
  510.         bset.b    #2,(A5)                 ;   set CTL to output
  511.         bclr.b    #2,(A4)                 ;   pulse CTL to cause FLAG int
  512.         or.b    #%00000111,(A4)         ;   set CTL = 1 and make sure
  513.                         ;   REQ will be one when we
  514.         bset.b    #1,(A5)                 ;   set ~REQ to output
  515.  
  516.         bclr.b    #1,(A4)                 ;   assert ~REQ
  517.  
  518.         bclr.b    #0,(A5)                 ;   make ~ACK an input
  519.                         ;   (note that REQ->0 before ACK->release)
  520.  
  521.         moveq.l #-1,D6            ;   D6 = # bytes written
  522.  
  523.         ;   INTERRUPTS ENABLED FOR TXFER (fully handshaked)
  524.         ;
  525.         ;   Address mark ~ACK, wait for ~ACK asserted
  526.  
  527. .wm10        btst.b    #0,(A4)
  528.         beq    .wm15
  529.         move.l    D5,D4            ;   D4 = timeout countdown
  530. .wm11        btst.b    #0,(A4)
  531.         beq    .wm15
  532.         add.l    #1,_ParDebug+20
  533.         subq.l    #1,D4
  534.         bne    .wm11
  535.         bra    .wmend
  536.  
  537.         ;   got ack, now set CTL = 0 (leaves at least one line 0 so
  538.         ;   nobody else thinks the bus is idle!)
  539.         ;
  540.         ;   note:   Since this is the address mark, and is sampled by
  541.         ;        the reader before it asserts ~ACK, I can set CTL
  542.         ;        = 0 now instead of waiting till after ~ACK is
  543.         ;        released.
  544.  
  545. .wm15        bclr.b    #2,(A4)                 ;   set CTL = 0 for duration of pkt
  546.         nop                ;   ???
  547.         bset.b    #1,(A4)                 ;   release ~REQ
  548.  
  549.  
  550.         moveq.l #0,D6            ;   # bytes written
  551.  
  552.         ;   DATA XFER LOOP
  553.         ;
  554.         ;   wait for ~ACK to be released (->1).  If no more bytes
  555.         ;   then skip to .wm50
  556.  
  557. .wm20
  558.         tst.l    D7            ;   more data in this buffer?
  559.         ble    .wm50            ;   nope.
  560.  
  561.         btst.b    #0,(A4)                 ;   wait ~ACK released
  562.         bne    .wm30
  563.         move.l    D5,D4            ;   D4 = timeout countdown
  564. .wm21        btst.b    #0,(A4)
  565.         bne    .wm30            ;   need the timeout here?
  566.         btst.b    #0,(A4)
  567.         bne    .wm30
  568.         add.l    #1,_ParDebug+24
  569.         subq.l    #1,D4
  570.         bne    .wm21
  571.         bra    .wmend
  572.  
  573.         ;   Assert ~REQ for this data byte and wait for ~ACK
  574.  
  575. .wm30
  576.         move.b    (A0)+,D0                ;   get next data byte
  577.         move.b    D0,(A1)                 ;   store data and
  578.         bclr.b    #1,(A4)                 ;   assert ~REQ
  579.  
  580.         move.b    (A0)+,D0                ;   get next data byte
  581.         subq.l    #2,D7            ;   one less byte (this and next)
  582.         addq.l    #1,D6            ;   # bytes written (this only)
  583.                         ;   (not valid until we get ACK
  584.                         ;    which is why the wmendsub
  585.  
  586.         btst.b    #0,(A4)                 ;   wait for ACK
  587.         beq    .wm40
  588.         btst.b    #0,(A4)
  589.         beq    .wm40
  590.         move.l    D5,D4            ;   D4 = timeout countdown
  591. .wm31        btst.b    #0,(A4)
  592.         beq    .wm40
  593.         add.l    #1,_ParDebug+28
  594.         subq.l    #1,D4
  595.         bne    .wm31
  596.         bra    .wmendsub
  597.  
  598.         ;   Have ~ACK, byte transmitted.  ++bytes written, --bytes left
  599.         ;   and loop
  600.  
  601. .wm40        move.b    D0,(A1)                 ; store second byte
  602.         bset.b    #1,(A4)                 ; release ~REQ
  603.  
  604.         addq.l    #1,D6            ; # bytes written
  605.  
  606.         bra    .wm20
  607.  
  608.         ;   Last byte in buffer has been transmitted.
  609.         ;
  610.         ;   Get next buffer in vector
  611.  
  612. .wm50        tst.l    (A3)
  613.         beq    .wm50a
  614.         move.l    (A3)+,A0                ;   buffer ptr
  615.         move.l    (A3)+,D7                ;   # bytes
  616.         bra    .wm20            ;   loop to top
  617.  
  618. .wm50a
  619.         ;   Last byte has been transmitted,
  620.         ;
  621.         ;   Wait for ~ACK to be released and then assert ~REQ with
  622.         ;   EOP & CTL = 1
  623.         ;
  624.         ;   (timing on read is that CTL is sampled when ~REQ is
  625.         ;   RELEASED so no timing window here)
  626.  
  627.         btst.b    #0,(A4)                 ;   Wait ~ACK released
  628.         beq    .wm50
  629.  
  630.         move.b    #0,(A1)                 ;   EOP mark (0)
  631.         bclr.b    #1,(A4)                 ;   assert ~REQ
  632.  
  633.         ;   Wait for ~ACK asserted
  634.  
  635.         btst.b    #0,(A4)
  636.         beq    .wm60
  637.         move.l    D5,D4
  638. .wm51        btst.b    #0,(A4)
  639.         beq    .wm60
  640.         add.l    #1,_ParDebug+32
  641.         subq.l    #1,D4
  642.         bne    .wm51
  643.         moveq.l #-3,D6            ;   EOP failed
  644.         bra    .wmend
  645.  
  646.         ;   Set CTL = 1 then release ~REQ, then wait for ~ACK released
  647.  
  648. .wm60        or.b    #%00000100,(A4) ;   set CTL = 1
  649.         or.b    #%00000110,(A4) ;   release ~REQ
  650.  
  651.         ;   Wait ~ACK released ?
  652.  
  653. .wm61        btst.b    #0,(A4)
  654.         beq    .wm61
  655.  
  656.         ;   Add D7 to D6.  This handles fixup if an odd number of bytes
  657.         ;   were requested written, D7 will be -1 (odd) or 0 (even) and
  658.         ;   D6 will be one too large (odd) or perfect (even)
  659.  
  660.         add.l    D7,D6
  661.  
  662.         bra    .wmend
  663.  
  664. .wmendsub    subq.l    #1,D6        ;   was ahead in count
  665.  
  666. .wmend        move.b    #0,(A2)         ;   set data port to input
  667.         and.b    #%11111000,(A5) ;   set data port for ctl lines to input
  668.  
  669.         move.l    D6,D0            ;   return value
  670.         movem.l (sp)+,D2-D7/A2-A6       ;   restore registers
  671.         rts
  672.  
  673.         ;   sum = LongCheckSum(buf, bytes)
  674.         ;   (buffer must be lw aligned and bytes must be multiples of 4)
  675.  
  676. _LongCheckSum:
  677.         moveq.l #0,D0            ;   D0 = accumulated checksum
  678.         move.l    4(sp),A0                ;   A0 = ptr
  679.         move.l    8(sp),D1                ;   D1 = bytes
  680.         beq    .pcrts
  681. .pc10        add.l    (A0)+,D0
  682.         subq.l    #4,D1
  683.         bgt    .pc10
  684.         tst.l    D1
  685.         bne    .pc20            ;   not multiple of 4 bytes!
  686. .pcrts        rts                ;   return checksum
  687. .pc20        illegal             ;   cause task-held msg
  688.         rts
  689.  
  690.         ;   Delays 10000 rough timeout loops, used to determine
  691.         ;   timeout on init
  692.  
  693. _Time10000:
  694.         move.l    #10000,D4
  695. t10        move.l    D4,D4
  696.         move.l    D4,D4
  697.         move.l    D4,D4
  698.         move.l    D4,D4
  699.         subq.l    #1,D4
  700.         bne    t10
  701.         rts
  702.  
  703.         END
  704.  
  705.